/***************************************************************************
 *   Copyright (C) 2007 by vasaka,,,   *
 *   vasaka@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "clusterpoint.h"
#include <list>
#include <math.h>

vector< Ctraveller::Shift > Ctraveller::Neighbours_sm=vector< Ctraveller::Shift >();
vector< Ctraveller::Shift > Ctraveller::Clique2_sm=vector< Ctraveller::Shift >();//two different cliques : and ..
vector< Ctraveller::Shift > Ctraveller::Clique3_sm=vector< Ctraveller::Shift >();//four of them, cannot be shifted to each other :. and .: and `: and :` 
vector< Ctraveller::Shift > Ctraveller::Clique4_sm=vector< Ctraveller::Shift >(); //hence there are 4 different cliques for a point, we need only one, cause shifting always will bring us to another clique of this type :: 

Ctraveller::Ctraveller ( short x, short y,CImage *im ) :
	        Parent(im),
          x_m(x),
          y_m(y)
{
  if (Neighbours_sm.size()==0) //should be sorted by distance
  {    
    Neighbours_sm.push_back ( Shift ( -1, 0 ) );//distance 1
    Neighbours_sm.push_back ( Shift ( 0,-1 ) );
    Neighbours_sm.push_back ( Shift ( 0, 1 ) );
    Neighbours_sm.push_back ( Shift ( 1, 0 ) );

    Neighbours_sm.push_back ( Shift ( 1,-1 ) );//distance sqrt(2)    
    Neighbours_sm.push_back ( Shift ( 1, 1 ) );
    Neighbours_sm.push_back ( Shift ( -1, 1 ) );    
    Neighbours_sm.push_back ( Shift ( -1,-1 ) );
    
    Neighbours_sm.push_back ( Shift ( -2, 0 ) );//distance 2
    Neighbours_sm.push_back ( Shift ( 0,-2 ) );
    Neighbours_sm.push_back ( Shift ( 0, 2 ) );
    Neighbours_sm.push_back ( Shift ( 2, 0 ) );        
    printf("Neighbours Number %d\n",Neighbours_sm.size());
  }
  
  if (Clique2_sm.size()==0) //cliques one by one,  only neyghbours are stored
  {    
	Clique2_sm.push_back ( Shift ( 1, 0 ) );//clique 1

	Clique2_sm.push_back ( Shift ( 0, 1 ) );//clique 2  
  } 
  
  if (Clique3_sm.size()==0) //cliques one by one,  only neyghbours are stored
  {    
	Clique3_sm.push_back ( Shift ( 1, 0 ) );//clique 1
	Clique3_sm.push_back ( Shift ( 0, 1 ) );

	Clique3_sm.push_back ( Shift ( 1, 0 ) );//clique 2
	Clique3_sm.push_back ( Shift ( 0, -1 ) );
	
	Clique3_sm.push_back ( Shift ( -1, 0 ) );//clique 3
	Clique3_sm.push_back ( Shift ( 0, -1 ) );	
	
	Clique3_sm.push_back ( Shift ( -1, 0 ) );//clique 4
	Clique3_sm.push_back ( Shift ( 0, 1 ) );	
  }  
  
  if (Clique4_sm.size()==0) //cliques one by one,  only neyghbours are stored
  {    
	Clique4_sm.push_back ( Shift ( 1, 0 ) );//clique 1, and only one is needed
	Clique4_sm.push_back ( Shift ( 0, 1 ) );
	Clique4_sm.push_back ( Shift ( 1, 1 ) );
  }    
}

template<typename MARK>
list< Ctraveller > Ctraveller::GetNeighbours(MARK Mark_,bool (CImage::*AdjFunc_)(int, int,int, int), vector< Shift > Neighbours_) const
{
  list< Ctraveller > tttList;
  MARK Mark2_ = CImage::InvertMark(Mark_);

  for (vector< Shift >::iterator CP = Neighbours_.begin();(CP!=Neighbours_.end());CP++)
  {
    int xx = CP->x;
    int yy = CP->y;
    if (Parent->validCoordinates(x_m+xx,y_m+yy))
    {
      if ( ((Parent->*AdjFunc_)(x_m,y_m,x_m+xx,y_m+yy)) && (Parent->IfMarked(x_m+xx, y_m+yy, Mark2_)))
      {
        Parent->SetMark (x_m+xx, y_m+yy, Mark_);
        tttList.push_back ( Ctraveller (  x_m+xx,y_m+yy ,Parent ) );
      }
    }
  }
  return tttList;
}

template<typename MARK>
list< Ctraveller > Ctraveller::GetNeighbours(MARK Mark_,bool (CImage::*AdjFunc_)(int, int,int, int), vector< Shift >::iterator begin_, vector< Shift >::iterator end_) const
{
  list< Ctraveller > tttList;
  MARK Mark2_ = CImage::InvertMark(Mark_);

  for (vector< Shift >::iterator CP = begin_;(CP!=end_);CP++)
  {
    int xx = CP->x;
    int yy = CP->y;
    if (Parent->validCoordinates(x_m+xx,y_m+yy))
    {
      if ( ((Parent->*AdjFunc_)(x_m,y_m,x_m+xx,y_m+yy)) && (Parent->IfMarked(x_m+xx, y_m+yy, Mark2_)))
      {
        Parent->SetMark (x_m+xx, y_m+yy, Mark_);
        tttList.push_back ( Ctraveller (  x_m+xx,y_m+yy ,Parent ) );
      }
    }
  }
  return tttList;
}

//----------------------------------------------------------------
//algorithms
//returns those points from neighbourhood which belongs to the seed's cluster
template<class MARK>
unsigned int AddNeighbors ( Ctraveller Point,list<Ctraveller> &Cluster,MARK Mark_ )
{
	list< Ctraveller > Neighbours = Point.GetNeighbours(Mark_,&CImage::IfAdjacentDist,Ctraveller::Neighbours_sm.begin(),Ctraveller::Neighbours_sm.begin()+7);
	int ret_ = Neighbours.size();
	Cluster.splice(Cluster.end(),Neighbours);
	return ret_;
}

unsigned int NeighborsResponce ( const Ctraveller &Point ) //redo it for getting two iterators or list
{
	list< Ctraveller > Neighbours = Point.GetNeighbours(CImage::True,&CImage::IfAdjacentTrue,Ctraveller::Neighbours_sm);
	int responce=Point.GetColorBitmap();
	for ( list< Ctraveller >::iterator CurrentPosition = Neighbours.begin();CurrentPosition!=Neighbours.end();CurrentPosition++ )
	{
		responce+=CurrentPosition->GetColorBitmap();
	}
	//return Neighbours.size() ? responce/(Neighbours.size()+1):0;
	return responce/(Neighbours.size()+1);
}
//Mark cluster starting from a seed point
template<class MARK>
unsigned int MarkClaster ( const Ctraveller &StartPoint,MARK Mark_ ) //set mark visited at every Cluster point
{
  unsigned int clSize_ = 0;
  list<Ctraveller> Cluster;
  Cluster.push_back ( StartPoint );
  StartPoint.SetMark(Mark_);
  for ( list<Ctraveller>::iterator CurrentPosition = Cluster.begin();CurrentPosition!=Cluster.end();CurrentPosition=Cluster.erase(CurrentPosition) )
  {
    clSize_ += AddNeighbors ( *CurrentPosition,Cluster,Mark_ );    
  }
  return clSize_;
}

//this function alters Cluster format image
unsigned int PaintClaster ( const Ctraveller &StartPoint,CImage::MarkGeneral MarkG_,CImage::MarkVisited Mark_  )//set color m and label n at every Cluster point
{
  unsigned int clSize_ = 0;
  list<Ctraveller> Cluster;
  Cluster.push_back ( StartPoint );
  StartPoint.SetMark(Mark_);
  for ( list<Ctraveller>::iterator CurrentPosition = Cluster.begin();CurrentPosition!=Cluster.end();CurrentPosition=Cluster.erase(CurrentPosition) )
  {
    clSize_ += AddNeighbors ( *CurrentPosition,Cluster,Mark_ );
    CurrentPosition->SetMark(MarkG_);    
  }
  return clSize_;
}

//this function alters bitmap format image
unsigned int PaintClasterOnBitmap ( const Ctraveller &StartPoint,int m,CImage::MarkVisited Mark_)//set color m and label n at every Cluster point
{
  int clSize_ = 0;
  list<Ctraveller> Cluster;
  Cluster.push_back ( StartPoint );
  StartPoint.SetMark(Mark_);
  for ( list<Ctraveller>::iterator CurrentPosition = Cluster.begin();CurrentPosition!=Cluster.end();Cluster.erase(CurrentPosition) )
  {
    clSize_ += AddNeighbors ( *CurrentPosition,Cluster,Mark_); //to really save start state should mark it back after
    CurrentPosition->SetColorBitmap(m);
  }
  return clSize_;
}

//paints cluster with its gibbs measure, given cliques model and potential function
unsigned int PaintGibbsMeasureOnBitmap ( const Ctraveller &StartPoint, CImage::MarkVisited Mark_)//set color m and label n at every Cluster point
{
  int clSize_ = 0;
  int cliqueNum_ = 0;
  int GibbsSum2 =0;
  int GibbsSum3 =0;
  int GibbsSum4 =0;
  list<Ctraveller> Cluster_;
  
  CImage::MarkGeneral MarkTemp_ = StartPoint.SwitchMark(CImage::Disabled); 
  Cluster_.push_back ( StartPoint );
  StartPoint.SetMark(MarkTemp_);
  for ( list<Ctraveller>::iterator CurrentPosition = Cluster_.begin();CurrentPosition!=Cluster_.end(); CurrentPosition=Cluster_.erase(CurrentPosition))
  {
    clSize_ += AddNeighbors ( *CurrentPosition,Cluster_,MarkTemp_); //to really save start state should mark it back after
	list< Ctraveller > clique_ = CurrentPosition->GetNeighbours(CImage::True,&CImage::IfAdjacentTrue,Ctraveller::Clique2_sm.begin(),Ctraveller::Clique2_sm.begin()+1);
	if (clique_.size() == 1)
	{
	  GibbsSum2 +=  abs(CurrentPosition->GetColorBitmap()-clique_.begin()->GetColorBitmap());
	  ++cliqueNum_;
	}
	clique_ = CurrentPosition->GetNeighbours(CImage::True,&CImage::IfAdjacentTrue,Ctraveller::Clique2_sm.begin()+1,Ctraveller::Clique2_sm.begin()+2);
	if (clique_.size() == 1)
	{
	  GibbsSum2 +=  abs(CurrentPosition->GetColorBitmap()-clique_.begin()->GetColorBitmap());
	  ++cliqueNum_;
	}
  }
  
  Cluster_.push_back ( StartPoint );
  StartPoint.SetMark(Mark_);
  for ( list<Ctraveller>::iterator CurrentPosition = Cluster_.begin();CurrentPosition!=Cluster_.end(); CurrentPosition=Cluster_.erase(CurrentPosition))
  {
	AddNeighbors ( *CurrentPosition,Cluster_,Mark_);
    CurrentPosition->SetColorBitmap(10*GibbsSum2/(cliqueNum_+1));
  }  
    
  return clSize_;
}

unsigned int CopyClasterOnBitmap ( const Ctraveller &StartPoint,CImage::MarkVisited Mark_)//set color m and label n at every Cluster point
{
  int clSize_ = 0;
  list<Ctraveller> Cluster;
  Cluster.push_back ( StartPoint );
  StartPoint.SetMark(Mark_);
  for ( list<Ctraveller>::iterator CurrentPosition = Cluster.begin();CurrentPosition!=Cluster.end();CurrentPosition=Cluster.erase(CurrentPosition) )
  {
    clSize_ += AddNeighbors ( *CurrentPosition,Cluster,Mark_); //to really save start state should mark it back after
    CurrentPosition->SetColorBitmap(CurrentPosition->GetColorBitmap());    
  }
  return clSize_;
}

unsigned int FilterClasterOnBitmap ( const Ctraveller &StartPoint,CImage::MarkVisited Mark_)//set color m and label n at every Cluster point
{
  int clSize_ = 0;
  list<Ctraveller> Cluster;
  Cluster.push_back ( StartPoint );
  StartPoint.SetMark(Mark_);
  for ( list<Ctraveller>::iterator CurrentPosition = Cluster.begin();CurrentPosition!=Cluster.end(); CurrentPosition=Cluster.erase(CurrentPosition))
  {
    clSize_ += AddNeighbors ( *CurrentPosition,Cluster,Mark_); //to really save start state should mark it back after
    CurrentPosition->SetColorBitmap(NeighborsResponce(*CurrentPosition));
    
  }
  return clSize_;
}

void CImage::Resize ( int* img_, int w_,int h_ )
{
  Width_m = w_;
  Height_m = h_;
  Points_m.resize(Width_m*Height_m);
  img_m = img_;
  printf("Resized CImage to %ix%i\n",Width_m,Height_m);
}

void CImage::SetPointBitmap ( int x, int y, int color )
{
  if ( ( x>=0 ) && ( y>=0 ) && ( x<Width_m ) && ( y< Height_m ) )
  {
	  imgout_m[x+Width_m*y]=color;
  }
  else
  {
    printf("Error wrong point acces in CImage::SetPointBitmap(...) with x=%i y=%i\n",x,y);
  }
}

int CImage::GetPointBitmap ( int x, int y)
{
  if ( ( x>=0 ) && ( y>=0 ) && ( x<Width_m ) && ( y< Height_m ) )
  {
	  return img_m[x+Width_m*y]&0x0000ff;
  }
  else
  {
    printf("Error wrong point acces in CImage::GetPointBitmap(...) with x=%i y=%i\n",x,y);
  }
  return 0;
}

template unsigned int MarkClaster<CImage::MarkVisited> ( const Ctraveller &StartPoint,CImage::MarkVisited Mark_);
template unsigned int MarkClaster<CImage::MarkDeleted> ( const Ctraveller &StartPoint,CImage::MarkDeleted Mark_);


